/* DocumentIcon.m:
 * You may freely copy, distribute, and reuse the code in this example.
 * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
 * fitness for any particular use.
 *
 * Written by Adam Hertz
 * Modified: Mike Riggs, Mai Nguyen
 *
 */

#import <dbkit/dbkit.h>
#import "DocumentIcon.h"

@implementation DocumentIcon
- initFrame:(const NXRect *)frameRect
{
    const char *dragTypes;
    [super initFrame:frameRect];
    dragTypes = NXFilenamePboardType;
    [self registerForDraggedTypes:&dragTypes count: 1];
    return self;
}

- free
{
    [self unregisterDraggedTypes];
    return [super free];
}


- drawSelf:(const NXRect *)rects :(int)rectCount
{
    NXRect imageRect;
    NXSize imageSize;
    NXPoint drawOrigin;
    
    NXDrawGrayBezel(&bounds, rects);
    imageRect.origin.x    = bounds.origin.x    + 2;
    imageRect.origin.y    = bounds.origin.y    + 2;
    imageRect.size.width  = bounds.size.width  - 4;
    imageRect.size.height = bounds.size.height - 4;

    PSgsave();
    NXRectClip(&imageRect);
    if (image != nil) {
	[image getSize:&imageSize];
	drawOrigin = imageRect.origin;
	drawOrigin.x += (imageRect.size.width - imageSize.width) / 2;
	drawOrigin.y += (imageRect.size.height - imageSize.height) / 2;
	[image composite:NX_SOVER toPoint:&drawOrigin];
    }
    PSgrestore();

    return self;
}

#define mask (NX_LMOUSEUPMASK|NX_LMOUSEDRAGGEDMASK)
#define Shift(e) (e->flags&(NX_NEXTLSHIFTKEYMASK|NX_NEXTRSHIFTKEYMASK))
#ifndef abs
#define abs(x) (((x)<0)? -(x) : (x))
#endif

int
mouseMoved(NXPoint *o, int n) { /* true if mouse moves > n pixels from 'o' */
	NXEvent *e;
	NXPoint p;
	float d;
	do {
		e = [NXApp getNextEvent:mask];
		p = e->location;
		d = abs(p.x-o->x);
		if (d < abs(p.y-o->y)) d = abs(p.y-o->y);
	} while (e->type != NX_LMOUSEUP && d<n);
	*o = p;
	return e->type != NX_LMOUSEUP;
}

- mouseDown: (NXEvent *) e
{
    NXPoint	hitPoint;
    int		oldMask;
    NXEvent	saveEvent;
    Pasteboard	*dragPasteboard;

		/* Call the workspace protocol to open the file at a double-click */
    if( e->data.mouse.click > 1
	    && filename && *filename) {
	[[Application workspace] openFile: filename];
    }

    oldMask = [window eventMask];
    [window setEventMask:(oldMask|mask)];
    saveEvent = *e;
    hitPoint = e->location;

    if (mouseMoved(&hitPoint,4)) {
	NXRect	dragRect;
	
	if( filename && *filename) {
	    [self convertPoint: &hitPoint fromView: nil];
	    [self getBounds: &dragRect];
	    
	    dragPasteboard = [Pasteboard newName: NXDragPboard];
	    [dragPasteboard declareTypes: &NXFilenamePboardType num: 1 owner: nil];
	    [dragPasteboard writeType: NXFilenamePboard data: filename
		    length: strlen( filename)];
	    
	    [self dragImage:image at:&(dragRect.origin) offset:&hitPoint
		    event:&saveEvent pasteboard:dragPasteboard
			source:self slideBack: YES];
		}
    }

    return [super mouseDown: e];
}

- (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
{
    return NX_DragOperationCopy;
}

- setTarget:anObject			{target = anObject; return self;}
- setAction:(SEL)aSelector		{action = aSelector; return self;}
- target				{return target;}
- (SEL)action				{return action;}

- (const char *) stringValue
{
    return filename;
}

- setStringValue:(const char *)aString
{
    int                 len;

    if (filename)
	NXZoneFree([self zone], (void *)filename);
	filename = NULL;
    if (aString) {
	filename = NXCopyStringBufferFromZone(aString,[self zone]);
	if (filename && *filename && aString) {
	    for (len = strlen(filename) - 1; len > 0; len--) {
		if (filename[len] == ' ') {
		    filename[len] = '\0';
		} else
		    break;
	    }
	    image = [[Application workspace] getIconForFile:filename];
	    [self display];
	}
    }
    return self;
}



/**********************************************************************/
/*                            Archiving                               */

- read:(NXTypedStream *)stream
{
    const char *dragTypes = NXFilenamePboardType;
    [super read: stream];
    [self registerForDraggedTypes:&dragTypes count: 1];
    return self;
}

/**********************************************************************/
/*                            Dragging                                */

- (NXDragOperation) draggingEntered: sender
{
    id dragPasteboard;
    char *path;
    int length;

    dragPasteboard = [sender draggingPasteboard];

    if( ([dragPasteboard readType:NXFilenamePboardType
		data:&path length:&length])
	    && (path && *path && *path == '/')) {
	return  NX_DragOperationCopy;
    }

    return NX_DragOperationNone;
}



- (BOOL)performDragOperation:(id <NXDraggingInfo>)sender
{
    char *path;
    int length;
    id dragPasteboard;

    dragPasteboard = [sender draggingPasteboard];

    if ([dragPasteboard readType:NXFilenamePboardType
		data:&path length:&length]) {

	char p[MAXPATHLEN];
	strncpy( p, path, length);
	p[length] = '\0';
	if( filename) NXZoneFree( [self zone], (void *)filename);
	filename = NULL;
	filename = NXCopyStringBuffer(p);
	image = [sender draggedImageCopy];
	[dragPasteboard deallocatePasteboardData:path length:length];
	
	[self display];
	if( target != nil)
	    [self sendAction:action to:target];
	    
	return YES;
    }

    return NO;
}


- draggingExited:sender
{
    return self;
}

/**********************************************************************/
/*                 DBCustomAssociation Implementation                 */
- updateForAssociation:association
{
    id                  val = [[DBValue alloc] init];

    [[[association fetchGroup] recordList] getValue:val
     forProperty:[association expression]
     at:[[association fetchGroup] currentRecord]];

    [self setStringValue:[val stringValue]];
    [val free];
    return self;
}


- associationContentsDidChange:association
{
    return [self updateForAssociation: association];
}

- associationSelectionDidChange:association
{
    return [self updateForAssociation: association];
}

@end


